"""
工作流定义和构建器

定义工作流结构和提供工作流构建功能。
"""

import uuid
from typing import Dict, Any, List, Optional, Set
from datetime import datetime
import logging
import json

from .nodes import WorkflowNode, NodeStatus, NodeType
from .context import WorkflowContext


class WorkflowDefinition:
    """
    工作流定义
    
    描述工作流的结构、节点和连接关系。
    """
    
    def __init__(self,
                 workflow_id: str = None,
                 name: str = None,
                 description: str = None,
                 version: str = "1.0.0",
                 config: Dict[str, Any] = None):
        self.workflow_id = workflow_id or str(uuid.uuid4())
        self.name = name or f"Workflow_{self.workflow_id[:8]}"
        self.description = description or ""
        self.version = version
        self.config = config or {}
        
        # 节点管理
        self.nodes: Dict[str, WorkflowNode] = {}
        self.node_order: List[str] = []
        
        # 元数据
        self.created_at = datetime.utcnow()
        self.updated_at = datetime.utcnow()
        self.tags: List[str] = []
        
        # 日志
        self.logger = logging.getLogger(f"workflow.definition.{self.workflow_id}")
    
    def add_node(self, node: WorkflowNode) -> None:
        """添加节点"""
        if node.node_id in self.nodes:
            raise ValueError(f"节点ID已存在: {node.node_id}")
        
        self.nodes[node.node_id] = node
        self.node_order.append(node.node_id)
        self.updated_at = datetime.utcnow()
        
        self.logger.debug(f"添加节点: {node.name} ({node.node_id})")
    
    def remove_node(self, node_id: str) -> Optional[WorkflowNode]:
        """移除节点"""
        if node_id not in self.nodes:
            return None
        
        node = self.nodes[node_id]
        
        # 移除所有连接
        for other_node in self.nodes.values():
            if node in other_node.inputs:
                other_node.remove_input(node)
            if node in other_node.outputs:
                other_node.remove_output(node)
        
        # 移除节点
        del self.nodes[node_id]
        if node_id in self.node_order:
            self.node_order.remove(node_id)
        
        self.updated_at = datetime.utcnow()
        self.logger.debug(f"移除节点: {node.name} ({node_id})")
        
        return node
    
    def get_node(self, node_id: str) -> Optional[WorkflowNode]:
        """获取节点"""
        return self.nodes.get(node_id)
    
    def get_nodes_by_type(self, node_type: NodeType) -> List[WorkflowNode]:
        """根据类型获取节点"""
        return [node for node in self.nodes.values() if node.node_type == node_type]
    
    def connect_nodes(self, from_node_id: str, to_node_id: str) -> bool:
        """连接两个节点"""
        from_node = self.get_node(from_node_id)
        to_node = self.get_node(to_node_id)
        
        if not from_node or not to_node:
            return False
        
        from_node.add_output(to_node)
        self.updated_at = datetime.utcnow()
        
        self.logger.debug(f"连接节点: {from_node.name} -> {to_node.name}")
        return True
    
    def disconnect_nodes(self, from_node_id: str, to_node_id: str) -> bool:
        """断开两个节点的连接"""
        from_node = self.get_node(from_node_id)
        to_node = self.get_node(to_node_id)
        
        if not from_node or not to_node:
            return False
        
        from_node.remove_output(to_node)
        self.updated_at = datetime.utcnow()
        
        self.logger.debug(f"断开连接: {from_node.name} -> {to_node.name}")
        return True
    
    def get_entry_nodes(self) -> List[WorkflowNode]:
        """获取入口节点（没有输入的节点）"""
        return [node for node in self.nodes.values() if not node.inputs]
    
    def get_exit_nodes(self) -> List[WorkflowNode]:
        """获取出口节点（没有输出的节点）"""
        return [node for node in self.nodes.values() if not node.outputs]
    
    def validate(self) -> List[str]:
        """验证工作流定义"""
        errors = []
        
        # 检查是否有节点
        if not self.nodes:
            errors.append("工作流必须包含至少一个节点")
            return errors
        
        # 检查是否有入口节点
        entry_nodes = self.get_entry_nodes()
        if not entry_nodes:
            errors.append("工作流必须有至少一个入口节点")
        
        # 检查是否有出口节点
        exit_nodes = self.get_exit_nodes()
        if not exit_nodes:
            errors.append("工作流必须有至少一个出口节点")
        
        # 检查循环依赖
        if self._has_cycles():
            errors.append("工作流存在循环依赖")
        
        # 检查孤立节点
        isolated_nodes = self._find_isolated_nodes()
        if isolated_nodes:
            errors.append(f"发现孤立节点: {[node.name for node in isolated_nodes]}")
        
        # 验证每个节点
        for node in self.nodes.values():
            node_errors = node.validate_config()
            for error in node_errors:
                errors.append(f"节点 {node.name}: {error}")
        
        return errors
    
    def _has_cycles(self) -> bool:
        """检查是否存在循环依赖"""
        visited = set()
        rec_stack = set()
        
        def dfs(node_id: str) -> bool:
            if node_id in rec_stack:
                return True
            if node_id in visited:
                return False
            
            visited.add(node_id)
            rec_stack.add(node_id)
            
            node = self.nodes[node_id]
            for output_node in node.outputs:
                if dfs(output_node.node_id):
                    return True
            
            rec_stack.remove(node_id)
            return False
        
        for node_id in self.nodes:
            if node_id not in visited:
                if dfs(node_id):
                    return True
        
        return False
    
    def _find_isolated_nodes(self) -> List[WorkflowNode]:
        """查找孤立节点"""
        # 从入口节点开始遍历
        reachable = set()
        entry_nodes = self.get_entry_nodes()
        
        def dfs(node: WorkflowNode):
            if node.node_id in reachable:
                return
            reachable.add(node.node_id)
            for output_node in node.outputs:
                dfs(output_node)
        
        for entry_node in entry_nodes:
            dfs(entry_node)
        
        # 找出不可达的节点
        isolated = []
        for node in self.nodes.values():
            if node.node_id not in reachable:
                isolated.append(node)
        
        return isolated
    
    def get_execution_order(self) -> List[List[WorkflowNode]]:
        """获取执行顺序（拓扑排序）"""
        # 计算每个节点的入度
        in_degree = {node_id: 0 for node_id in self.nodes}
        for node in self.nodes.values():
            for output_node in node.outputs:
                in_degree[output_node.node_id] += 1
        
        # 拓扑排序
        levels = []
        remaining_nodes = set(self.nodes.keys())
        
        while remaining_nodes:
            # 找到当前层级的节点（入度为0）
            current_level = []
            for node_id in list(remaining_nodes):
                if in_degree[node_id] == 0:
                    current_level.append(self.nodes[node_id])
                    remaining_nodes.remove(node_id)
            
            if not current_level:
                # 如果没有入度为0的节点，说明有循环
                break
            
            levels.append(current_level)
            
            # 更新入度
            for node in current_level:
                for output_node in node.outputs:
                    if output_node.node_id in remaining_nodes:
                        in_degree[output_node.node_id] -= 1
        
        return levels
    
    def reset_all_nodes(self) -> None:
        """重置所有节点状态"""
        for node in self.nodes.values():
            node.reset()
        self.logger.debug("重置所有节点状态")
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取工作流统计信息"""
        node_types = {}
        node_statuses = {}
        
        for node in self.nodes.values():
            # 统计节点类型
            node_type = node.node_type.value
            node_types[node_type] = node_types.get(node_type, 0) + 1
            
            # 统计节点状态
            node_status = node.status.value
            node_statuses[node_status] = node_statuses.get(node_status, 0) + 1
        
        return {
            'workflow_id': self.workflow_id,
            'name': self.name,
            'version': self.version,
            'total_nodes': len(self.nodes),
            'node_types': node_types,
            'node_statuses': node_statuses,
            'entry_nodes': len(self.get_entry_nodes()),
            'exit_nodes': len(self.get_exit_nodes()),
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat()
        }
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'workflow_id': self.workflow_id,
            'name': self.name,
            'description': self.description,
            'version': self.version,
            'config': self.config,
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat(),
            'tags': self.tags,
            'nodes': {node_id: node.to_dict() for node_id, node in self.nodes.items()},
            'node_order': self.node_order,
            'statistics': self.get_statistics()
        }
    
    def to_json(self) -> str:
        """转换为JSON字符串"""
        return json.dumps(self.to_dict(), indent=2, ensure_ascii=False)
    
    def save_to_file(self, file_path: str) -> None:
        """保存到文件"""
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(self.to_json())
        self.logger.info(f"工作流定义已保存到: {file_path}")
    
    def __str__(self) -> str:
        """字符串表示"""
        return f"WorkflowDefinition(id={self.workflow_id}, name={self.name}, nodes={len(self.nodes)})"
    
    def __repr__(self) -> str:
        """详细字符串表示"""
        return self.__str__()


class WorkflowBuilder:
    """
    工作流构建器

    提供流式API来构建工作流。
    """

    def __init__(self, name: str = None, description: str = None):
        self.workflow = WorkflowDefinition(
            name=name,
            description=description
        )
        self.current_node: Optional[WorkflowNode] = None
        self.logger = logging.getLogger("workflow.builder")

    def input_node(self, name: str = None, data: Dict[str, Any] = None, **kwargs) -> 'WorkflowBuilder':
        """添加输入节点"""
        from .nodes import InputNode

        config = kwargs.copy()
        if data:
            config['data'] = data

        node = InputNode(
            name=name or "输入节点",
            config=config
        )

        self.workflow.add_node(node)
        self.current_node = node
        return self

    def processing_node(self, name: str = None, processor=None, **kwargs) -> 'WorkflowBuilder':
        """添加处理节点"""
        from .nodes import ProcessingNode

        node = ProcessingNode(
            name=name or "处理节点",
            processor=processor,
            config=kwargs
        )

        self.workflow.add_node(node)

        # 自动连接到当前节点
        if self.current_node:
            self.workflow.connect_nodes(self.current_node.node_id, node.node_id)

        self.current_node = node
        return self

    def conditional_node(self, name: str = None, condition=None, **kwargs) -> 'WorkflowBuilder':
        """添加条件节点"""
        from .nodes import ConditionalNode

        node = ConditionalNode(
            name=name or "条件节点",
            condition=condition,
            config=kwargs
        )

        self.workflow.add_node(node)

        # 自动连接到当前节点
        if self.current_node:
            self.workflow.connect_nodes(self.current_node.node_id, node.node_id)

        self.current_node = node
        return self

    def parallel_node(self, name: str = None, **kwargs) -> 'WorkflowBuilder':
        """添加并行节点"""
        from .nodes import ParallelNode

        node = ParallelNode(
            name=name or "并行节点",
            config=kwargs
        )

        self.workflow.add_node(node)

        # 自动连接到当前节点
        if self.current_node:
            self.workflow.connect_nodes(self.current_node.node_id, node.node_id)

        self.current_node = node
        return self

    def sequential_node(self, name: str = None, **kwargs) -> 'WorkflowBuilder':
        """添加顺序节点"""
        from .nodes import SequentialNode

        node = SequentialNode(
            name=name or "顺序节点",
            config=kwargs
        )

        self.workflow.add_node(node)

        # 自动连接到当前节点
        if self.current_node:
            self.workflow.connect_nodes(self.current_node.node_id, node.node_id)

        self.current_node = node
        return self

    def output_node(self, name: str = None, output_key: str = None, **kwargs) -> 'WorkflowBuilder':
        """添加输出节点"""
        from .nodes import OutputNode

        config = kwargs.copy()
        if output_key:
            config['output_key'] = output_key

        node = OutputNode(
            name=name or "输出节点",
            config=config
        )

        self.workflow.add_node(node)

        # 自动连接到当前节点
        if self.current_node:
            self.workflow.connect_nodes(self.current_node.node_id, node.node_id)

        self.current_node = node
        return self

    def connect(self, from_node_name: str, to_node_name: str) -> 'WorkflowBuilder':
        """手动连接节点"""
        from_node = self._find_node_by_name(from_node_name)
        to_node = self._find_node_by_name(to_node_name)

        if from_node and to_node:
            self.workflow.connect_nodes(from_node.node_id, to_node.node_id)
        else:
            raise ValueError(f"找不到节点: {from_node_name} 或 {to_node_name}")

        return self

    def branch(self, node_name: str) -> 'WorkflowBuilder':
        """分支到指定节点"""
        node = self._find_node_by_name(node_name)
        if node:
            self.current_node = node
        else:
            raise ValueError(f"找不到节点: {node_name}")

        return self

    def set_config(self, **config) -> 'WorkflowBuilder':
        """设置工作流配置"""
        self.workflow.config.update(config)
        return self

    def set_tags(self, *tags) -> 'WorkflowBuilder':
        """设置工作流标签"""
        self.workflow.tags.extend(tags)
        return self

    def validate(self) -> List[str]:
        """验证工作流"""
        return self.workflow.validate()

    def build(self) -> WorkflowDefinition:
        """构建工作流"""
        # 验证工作流
        errors = self.validate()
        if errors:
            error_msg = "工作流验证失败:\n" + "\n".join(f"  - {error}" for error in errors)
            raise ValueError(error_msg)

        self.logger.info(f"工作流构建完成: {self.workflow.name}")
        return self.workflow

    def _find_node_by_name(self, name: str) -> Optional[WorkflowNode]:
        """根据名称查找节点"""
        for node in self.workflow.nodes.values():
            if node.name == name:
                return node
        return None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'WorkflowBuilder':
        """从字典创建构建器"""
        builder = cls(
            name=data.get('name'),
            description=data.get('description')
        )

        # 设置配置
        if 'config' in data:
            builder.workflow.config.update(data['config'])

        # 设置标签
        if 'tags' in data:
            builder.workflow.tags.extend(data['tags'])

        # 创建节点
        nodes_data = data.get('nodes', {})
        for node_id, node_data in nodes_data.items():
            node = builder._create_node_from_dict(node_data)
            if node:
                builder.workflow.nodes[node_id] = node
                builder.workflow.node_order.append(node_id)

        # 建立连接
        for node_id, node_data in nodes_data.items():
            node = builder.workflow.nodes[node_id]
            for output_node_id in node_data.get('outputs', []):
                if output_node_id in builder.workflow.nodes:
                    builder.workflow.connect_nodes(node_id, output_node_id)

        return builder

    def _create_node_from_dict(self, node_data: Dict[str, Any]) -> Optional[WorkflowNode]:
        """从字典创建节点"""
        from .nodes import (
            InputNode, OutputNode, ProcessingNode,
            ConditionalNode, ParallelNode, SequentialNode
        )

        node_type = node_data.get('node_type')
        node_classes = {
            'input': InputNode,
            'output': OutputNode,
            'processing': ProcessingNode,
            'conditional': ConditionalNode,
            'parallel': ParallelNode,
            'sequential': SequentialNode
        }

        node_class = node_classes.get(node_type)
        if not node_class:
            self.logger.error(f"未知节点类型: {node_type}")
            return None

        try:
            node = node_class(
                node_id=node_data.get('node_id'),
                name=node_data.get('name'),
                description=node_data.get('description'),
                config=node_data.get('config', {})
            )
            return node
        except Exception as e:
            self.logger.error(f"创建节点失败: {e}")
            return None

    @classmethod
    def from_json(cls, json_str: str) -> 'WorkflowBuilder':
        """从JSON字符串创建构建器"""
        data = json.loads(json_str)
        return cls.from_dict(data)

    @classmethod
    def from_file(cls, file_path: str) -> 'WorkflowBuilder':
        """从文件创建构建器"""
        with open(file_path, 'r', encoding='utf-8') as f:
            json_str = f.read()
        return cls.from_json(json_str)
